/*
 * SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 * Description   : udk common define
 */

#ifndef UDK_COMMON_H
#define UDK_COMMON_H

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

#define USEC_PER_MSEC 1000

#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
#define UDK_STD_C11 __extension__
#else
#define UDK_STD_C11
#endif

#ifdef UDK_ARCH_ARM64
#define UDK_MAX_LCORE_DEFAULT 256 /* arm 256 */
#else
#define UDK_MAX_LCORE_DEFAULT 576 /* x86 default 576 */
#endif

extern uint16_t g_udk_max_lcore;
#define UDK_MAX_LCORE g_udk_max_lcore

static inline void udk_max_lcore_set(uint16_t max_lcore)
{
    g_udk_max_lcore = max_lcore;
}

#define UDK_MAX_NUMA_NODES 8
#define UDK_SOCKET_ID_ANY (-1) /* Any NUMA socket. */

#ifdef UDK_ARCH_ARM64
#define UDK_CACHE_LINE_SIZE 128 /* aarch64 cacheline size */
#else
#define UDK_CACHE_LINE_SIZE 64 /* default(x86) cacheline size */
#endif

#define UDK_CACHE_LINE_MASK (UDK_CACHE_LINE_SIZE - 1)

#define UDK_CACHE_LINE_MIN_SIZE 64

#undef UDK_HOT_REPLACE
#define UDK_HOT_REPLACE 1

#define UDK_DIM(a) (sizeof (a) / sizeof ((a)[0]))

#define UDK_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
#define UDK_PTR_SUB(ptr, x) ((void*)((uintptr_t)(ptr) - (x)))
#define UDK_PTR_DIFF(ptr1, ptr2) ((uintptr_t)(ptr1) - (uintptr_t)(ptr2))
#define UDK_ALIGN_FLOOR(val, align) (typeof(val))((val) & (~((typeof(val))((align) - 1))))
#define UDK_PTR_ALIGN_FLOOR(ptr, align) ((typeof(ptr))UDK_ALIGN_FLOOR((uintptr_t)(ptr), (align)))
#define UDK_ALIGN_CEIL(val, align) UDK_ALIGN_FLOOR(((val) + ((typeof(val)) (align) - 1)), align)
#define UDK_ALIGN(val, align) UDK_ALIGN_CEIL(val, align)
#define UDK_PTR_ALIGN_CEIL(ptr, align) UDK_PTR_ALIGN_FLOOR((typeof(ptr))UDK_PTR_ADD((ptr), (align) - 1), (align))
#define UDK_PTR_ALIGN(ptr, align) UDK_PTR_ALIGN_CEIL(ptr, align)
#define UDK_ALIGN_MUL_CEIL(v, mul) ((((v) + (typeof(v))(mul)-1) / ((typeof(v))(mul))) * (typeof(v))(mul))
#define UDK_ALIGN_MUL_FLOOR(v, mul) (((v) / ((typeof(v))(mul))) * (typeof(v))(mul))
#define UDK_ALIGN_MUL_NEAR(v, mul)                    \
    ({                                                \
        typeof(v)ceil = UDK_ALIGN_MUL_CEIL(v, mul);   \
        typeof(v)floor = UDK_ALIGN_MUL_FLOOR(v, mul); \
        (ceil - (v)) > ((v)-floor) ? floor : ceil;    \
    })

#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif /* likely */

#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif /* unlikely */

#ifndef offsetof
/** Return the offset of a field in a structure. */
#define offsetof(TYPE, MEMBER)  __builtin_offsetof(TYPE, MEMBER)
#endif

#define udk_aligned(a) __attribute__((__aligned__(a)))
#define udk_cache_aligned udk_aligned(UDK_CACHE_LINE_SIZE)
#define udk_cache_min_aligned udk_aligned(UDK_CACHE_LINE_MIN_SIZE)
#define udk_packed __attribute__((__packed__))
#define udk_unused __attribute__((__unused__))

/* Force a function to be inlined */
#define udk_force_inline inline __attribute__((always_inline))

#define UDK_REF_VAR(x) (void)(x)

#define UDK_PRIORITY_CLASS  120
#define UDK_PRIORITY_LAST   65535
#define UDK_PRIORITY(prio)  UDK_PRIORITY_##prio

/* Run function before main() with specified priority. */
#ifndef UDK_INIT_PRIO
#define UDK_INIT_PRIO(func, prio) \
    static void __attribute__((constructor(UDK_PRIORITY(prio)), used)) func(void)
#endif

/* Run function before main() with low priority. */
#define UDK_INIT(func)  UDK_INIT_PRIO(func, LAST)

/* macro for min and max */
#define UDK_MIN(a, b) \
    __extension__ ({ \
        typeof (a) _a = (a); \
        typeof (b) _b = (b); \
        _a < _b ? _a : _b; \
    })

#define UDK_MAX(a, b) \
    __extension__ ({ \
        typeof (a) _a = (a); \
        typeof (b) _b = (b); \
        _a > _b ? _a : _b; \
    })

static inline uint32_t udk_bsf32(uint32_t v)
{
    return (uint32_t)__builtin_ctz(v);
}

#define UDK_MAKE_QWORD(val_h32, val_l32) ((((uint64_t)(val_h32)) << 32) | ((uint64_t)(val_l32)))

#ifndef udk_iova_t
typedef uint64_t udk_iova_t;
#endif

#define UDK_BAD_IOVA ((udk_iova_t) - 1)

/* Structure alignment markers */
/* Generic marker for any place in a structure. */
__extension__ typedef void    *UDK_MARKER[0];
/* Marker for 1B alignment in a structure. */
__extension__ typedef uint8_t  UDK_MARKER8[0];
/* Marker for 2B alignment in a structure. */
__extension__ typedef uint16_t UDK_MARKER16[0];
/* Marker for 4B alignment in a structure. */
__extension__ typedef uint32_t UDK_MARKER32[0];
/* Marker for 8B alignment in a structure. */
__extension__ typedef uint64_t UDK_MARKER64[0];

/* ========debug======== */
#ifdef UDK_ENABLE_ASSERT
#define UDK_ASSERT(exp) UDK_VERIFY(exp)
#else
#define UDK_ASSERT(exp) \
    do {                \
    } while (0)
#endif

#define udk_panic(...) udk_panic_handle(__func__, __VA_ARGS__)

#define UDK_VERIFY(exp)                                                   \
    do {                                                                  \
        if (unlikely(!(exp))) {                                           \
            udk_panic("line %d\tassert \"%s\" failed\n", __LINE__, #exp); \
        }                                                                 \
    } while (0)

#define UDK_BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2 * (!!(condition))]))

/* ===========udk config============= */
enum udk_proc_type_t {
    UDK_PROC_PRIMARY = 0,
    UDK_PROC_SECONDARY,
    UDK_PROC_INVALID
};

/* Aligns a 32-bit number to the next power of 2 */
static inline uint32_t udk_align32pow2(uint32_t x)
{
    x--;
    x |= x >> 1;  // 右移1位并与原值按位或，则这个数高2位为1.
    x |= x >> 2;  // 右移2位并与原值按位或，则这个数高4位为1.
    x |= x >> 4;  // 右移4位并与原值按位或，则这个数高8位为1.
    x |= x >> 8;  // 右移8位并与原值按位或，则这个数高16位为1.
    x |= x >> 16; // 右移16位并与原值按位或，则这个数高32位为1.

    return x + 1; // 加1则所有1前进一位变0，即2的N次幂.
}

static inline int udk_is_power_of_2(uint32_t n)
{
    return (n != 0) && (!(n & (n - 1)));
}

/* Generate a pseudo-random value between 0 and (1<<64)-1 */
static inline uint64_t udk_rand(void)
{
    return UDK_MAKE_QWORD(lrand48(), lrand48());
}

static inline unsigned long int udk_get_ptr(const void *p)
{
    #ifdef UDK_MEM_PTR_DEBUG
    return (uintptr_t)p;
    #else
    return !!p;
    #endif
}

int udk_process_type(void);
int udk_init(enum udk_proc_type_t type);
void udk_deinit(void);
int udk_strsplit(char *string, int stringlen, char **tokens, int maxtokens, char delim);
void udk_hexdump(FILE *f, const char *title, const void *buf, uint32_t len);
void udk_dump_stack(void);
void udk_panic_handle(const char *func_name, const char *format, ...);
#endif